// 从 vite 库中导入 CSSOptions 和 UserConfig 类型，用于定义 Vite 配置的类型
import type { CSSOptions, UserConfig } from 'vite';

// 从 '../typing' 模块中导入 DefineApplicationOptions 类型，用于定义应用配置选项的类型
import type { DefineApplicationOptions } from '../typing';

// 导入 Node.js 的 path 模块，用于处理和转换文件路径，同时解构出 relative 函数
import path, { relative } from 'node:path';

// 从 '@cwind/node-utils' 模块中导入 findMonorepoRoot 函数，用于查找 monorepo 的根目录
import { findMonorepoRoot } from '@cwind/node-utils';

// 从 'sass' 库中导入 NodePackageImporter 类，用于处理 Sass 包的导入
import { NodePackageImporter } from 'sass';
// 从 vite 库中导入 defineConfig、loadEnv 和 mergeConfig 函数，用于定义、加载环境变量和合并配置
import { defineConfig, loadEnv, mergeConfig } from 'vite';

// 从 '../options' 模块中导入默认的 importmap 选项和 PWA 选项
import { defaultImportmapOptions, getDefaultPwaOptions } from '../options';
// 从 '../plugins' 模块中导入加载应用插件的函数
import { loadApplicationPlugins } from '../plugins';
// 从 '../utils/env' 模块中导入加载并转换环境变量的函数
import { loadAndConvertEnv } from '../utils/env';
// 从 './common' 模块中导入获取公共配置的函数
import { getCommonConfig } from './common';

/**
 * 定义应用程序的 Vite 配置。
 *
 * @param {DefineApplicationOptions} [userConfigPromise] - 可选的用户配置选项，是一个异步函数，接收 Vite 配置对象作为参数。
 * @returns {Promise<UserConfig>} - 返回一个 Promise，解析为合并后的 Vite 配置对象。
 */
function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
  return defineConfig(async (config) => {
    // 调用用户提供的配置函数，获取用户配置
    const options = await userConfigPromise?.(config);
    // 加载并转换环境变量，解构出应用标题、基础路径、端口和其他环境配置
    const { appTitle, base, port, ...envConfig } = await loadAndConvertEnv();
    // 从 Vite 配置中解构出命令和模式
    const { command, mode } = config;
    // 从用户选项中解构出应用配置和 Vite 配置，若选项不存在则默认为空对象
    const { application = {}, vite = {} } = options || {};
    // 获取当前工作目录
    const root = process.cwd();
    // 判断是否为构建命令
    const isBuild = command === 'build';
    // 加载当前模式下的环境变量
    const env = loadEnv(mode, root);

    // 加载应用程序插件，传入各种插件配置选项
    const plugins = await loadApplicationPlugins({
      archiver: true,
      archiverPluginOptions: {},
      compress: false,
      compressTypes: ['brotli', 'gzip'],
      devtools: true,
      env,
      extraAppConfig: true,
      html: true,
      i18n: true,
      importmapOptions: defaultImportmapOptions,
      injectAppLoading: true,
      injectMetadata: true,
      isBuild,
      license: true,
      mode,
      nitroMock: !isBuild,
      nitroMockOptions: {},
      print: !isBuild,
      printInfoMap: {
        'Cwind Admin Docs': 'https://doc.cwind.pro',
      },
      pwa: true,
      pwaOptions: getDefaultPwaOptions(appTitle),
      vxeTableLazyImport: true,
      ...envConfig,
      ...application,
    });

    // 从应用配置中解构出是否注入全局 SCSS 的选项，默认为 true
    const { injectGlobalScss = true } = application;

    // 定义应用程序的 Vite 配置对象
    const applicationConfig: UserConfig = {
      // 应用的基础路径
      base,
      build: {
        rollupOptions: {
          output: {
            // 静态资源文件的命名规则
            assetFileNames: '[ext]/[name]-[hash].[ext]',
            // 代码块文件的命名规则
            chunkFileNames: 'js/[name]-[hash].js',
            // 入口文件的命名规则
            entryFileNames: 'jse/index-[name]-[hash].js',
          },
        },
        // 构建目标的 ECMAScript 版本
        target: 'es2015',
      },
      // 配置 CSS 相关选项
      css: createCssOptions(injectGlobalScss),
      esbuild: {
        // 在构建时移除 debugger 语句，可按需取消注释移除 console 语句
        drop: isBuild
          ? [
              // 'console',
              'debugger',
            ]
          : [],
        // 移除法律注释
        legalComments: 'none',
      },
      // 应用的插件列表
      plugins,
      server: {
        // 允许外部访问
        host: true,
        // 开发服务器的端口
        port,
        warmup: {
          // 预热文件列表，加快开发服务器启动速度
          clientFiles: [
            './index.html',
            './src/bootstrap.ts',
            './src/{views,layouts,router,store,api,adapter}/*',
          ],
        },
      },
    };

    // 合并公共配置和应用程序配置
    const mergedCommonConfig = mergeConfig(
      await getCommonConfig(),
      applicationConfig,
    );
    // 合并最终的公共配置和用户提供的 Vite 配置
    return mergeConfig(mergedCommonConfig, vite);
  });
}

/**
 * 创建 CSS 配置选项。
 *
 * @param {boolean} [injectGlobalScss] - 是否注入全局 SCSS 样式，默认为 true。
 * @returns {CSSOptions} - 返回 CSS 配置选项对象。
 */
function createCssOptions(injectGlobalScss = true): CSSOptions {
  // 查找 monorepo 的根目录
  const root = findMonorepoRoot();
  return {
    preprocessorOptions: injectGlobalScss
      ? {
          scss: {
            /**
             * 为 SCSS 文件添加额外的数据。
             *
             * @param {string} content - 原始的 SCSS 文件内容。
             * @param {string} filepath - SCSS 文件的路径。
             * @returns {string} - 添加额外数据后的 SCSS 内容。
             */
            additionalData: (content: string, filepath: string) => {
              // 获取文件相对于 monorepo 根目录的相对路径
              const relativePath = relative(root, filepath);
              // 如果文件在 apps 目录下，则注入全局样式
              if (relativePath.startsWith(`apps${path.sep}`)) {
                return `@use "@cwind/styles/global" as *;\n${content}`;
              }
              return content;
            },
            // 使用现代的 Sass API
            api: 'modern',
            // 使用 NodePackageImporter 处理 Sass 包的导入
            importers: [new NodePackageImporter()],
          },
        }
      : {},
  };
}

// 导出定义应用程序配置的函数
export { defineApplicationConfig };
